close all
clear all

io_block = 512;

ctl_sz   =   8;
key_sz   =  32;
info_sz  =  16;
ftr_sz   =  16;

obj_cnt_min = 2;
obj_cnt_max = 64;
obj_cnt_lvl = 12;

pair_framing = ctl_sz + key_sz + info_sz + ftr_sz;

val_min  = 0;
val_max  = 10*2^20 + io_block - pair_framing;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%

obj_footprint_min = io_block*ceil( ( io_block + pair_framing + val_min ) / io_block );
obj_footprint_max = io_block*ceil( ( io_block + pair_framing + val_max ) / io_block );

sb_footprint(1) = io_block + obj_cnt_max*obj_footprint_min;
lvl_cnt = 1;
while sb_footprint(lvl_cnt) < io_block + obj_cnt_min*obj_footprint_max;
  lvl_cnt++;
  sb_footprint(lvl_cnt) = io_block + obj_cnt_lvl*sb_footprint(lvl_cnt-1);
endwhile

szc_cnt = 0;
for lvl=1:lvl_cnt;
  for cnt=obj_cnt_max:-1:obj_cnt_min,
    szc_cnt++;
    fp                        = io_block*floor( ((sb_footprint(lvl)/io_block)-1) / cnt )
    obj_val_max(szc_cnt)      = fp - io_block - pair_framing;
    obj_footprint(szc_cnt)    = fp;
    obj_cnt(szc_cnt)          = min( floor( (sb_footprint(lvl) - io_block) / fp ), obj_cnt_max );
    parent_footprint(szc_cnt) = sb_footprint(lvl);
  endfor
endfor

[~,idx] = unique( obj_val_max, 'first' );
obj_val_max      = obj_val_max     (idx);
obj_footprint    = obj_footprint   (idx);
obj_cnt          = obj_cnt         (idx);
parent_footprint = parent_footprint(idx);
szc_cnt = length(obj_val_max);

% If we didn't get a sizeclass exactly tuned for val_max, create one

szc = find( obj_val_max>=val_max, 1 )
if obj_val_max(szc)>val_max,
  szc_cnt++;
  obj_val_max(szc_cnt)      = val_max;
  obj_footprint(szc_cnt)    = io_block + pair_framing + val_max;
  obj_cnt(szc_cnt)          = obj_cnt(szc);
  parent_footprint(szc_cnt) = parent_footprint(szc);

  [~,idx] = unique( obj_val_max, 'first' );
  obj_val_max      = obj_val_max     (idx);
  obj_footprint    = obj_footprint   (idx);
  obj_cnt          = obj_cnt         (idx);
  parent_footprint = parent_footprint(idx);
  szc_cnt = length(obj_val_max);
endif

printf( '#define FD_VINYL_VAL_MAX (%uUL) /* autogenerated */\n', val_max );
printf( '\n' );
printf( '#define FD_VINYL_DATA_VOL_FOOTPRINT (%uUL) /* autogenerated */\n', sb_footprint(lvl_cnt) ); % mem align for a vol header
printf( '\n' );
printf( '#define FD_VINYL_DATA_SZC_CNT (%uUL) /* autogenerated */\n', szc_cnt );
printf( '\n' );
printf( '######################################################################################################\n' );
printf( '#include \"fd_vinyl_data.h\"\n' );
printf( '\n' );
printf( '/* This table autogenerated\n' );
printf( '     io_block    %i\n', io_block    );
printf( '     ctl_sz      %i\n', ctl_sz      );
printf( '     key_sz      %i\n', key_sz      );
printf( '     info_sz     %i\n', info_sz     );
printf( '     ftr_sz      %i\n', ftr_sz      );
printf( '     obj_cnt_min %i\n', obj_cnt_min );
printf( '     obj_cnt_max %i\n', obj_cnt_max );
printf( '     obj_cnt_lvl %i\n', obj_cnt_lvl );
printf( '     val_min     %i\n', val_min     );
printf( '     val_max     %i\n', val_max     );
printf( '\n' );
printf( 'fd_vinyl_data_szc_cfg_t const fd_vinyl_data_szc_cfg[ FD_VINYL_DATA_SZC_CNT ] = {\n' );
for szc=1:szc_cnt,
  pfp  = parent_footprint(szc);
  pszc = find( pfp==obj_footprint, 1 );
  if isempty(pszc), pszc = szc_cnt+1; endif
  parent_szc(szc) = pszc;
  printf( '  /* %3u */ { %10uU, (ushort)%2u, (ushort)%3u }, // obj_footprint %10u sb_footprint %10u%s\n', szc-1, obj_val_max(szc),obj_cnt(szc), pszc-1, obj_footprint(szc), pfp, ifelse( obj_val_max(szc)==val_max, ' <- FD_VINYL_VAL_MAX', '' ) );
endfor
printf( '};\n' );

idx = find( parent_szc==(szc_cnt+1) );
if any( parent_footprint(idx)~=sb_footprint(lvl_cnt) ), error( 'hmmm' ); endif
